package com.xfdmao.fcat.coin.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.xfdmao.fcat.coin.entity.BtcHour;
import com.xfdmao.fcat.coin.huobi.api.ApiClient;
import com.xfdmao.fcat.coin.huobi.api.ApiException;
import com.xfdmao.fcat.coin.huobi.response.KlineResponse;
import com.xfdmao.fcat.coin.service.BtcHourService;
import com.xfdmao.fcat.coin.service.impl.BtcHourServiceImpl;
import com.xfdmao.fcat.common.controller.BaseController;
import com.xfdmao.fcat.common.util.DateUtil;
import com.xfdmao.fcat.common.util.JsonUtil;
import com.xfdmao.fcat.common.util.MathUtil;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;

/**
 * Created by fier on 2018/10/22
 */
@RestController
@RequestMapping("v1/btcHour")
public class BtcHourController{
    private static Logger logger = Logger.getLogger(BtcHourController.class);
    @Autowired
    private BtcHourService btcHourService;

    @Value("${coin.API_KEY}")
    private  String  API_KEY;

    @Value("${coin.API_SECRET}")
    private  String  API_SECRET;

    public static ApiClient  client;

    @GetMapping(value = "/getBtcHour")
    public JSONObject getBtcHour( @RequestParam("symbol") String symbol, @RequestParam("period") String period, @RequestParam("size") String size) {
        new Thread(() -> {
            try {
                if (client == null) {
                    client = new ApiClient(API_KEY, API_SECRET);
                }
                KlineResponse kline = client.kline(symbol, period, size);
                List<BtcHour> btcHours = new ArrayList<>();
                if (kline.getStatus().equals("ok")) {
                    JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(kline));
                    JSONArray jsonArray = jsonObject.getJSONArray("data");
                    logger.debug("获取到的data："+JSONArray.toJSONString(jsonArray));
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JSONObject jsonObject1 = jsonArray.getJSONObject(i);
                        BtcHour btcHour = JSONObject.toJavaObject(jsonObject1, BtcHour.class);
                        btcHour.setTime(new Date(btcHour.getId() * 1000));
                        btcHour.setSymbol(symbol);
                        btcHour.setPeriod(period);
                        btcHours.add(btcHour);
                    }
                }
                long maxId = 0;
                for (int i = 0; i < btcHours.size(); i++) {
                    BtcHour btcHour = btcHours.get(i);
                    if (maxId < btcHour.getId()) {
                        maxId = btcHour.getId();
                    }
                }
                Iterator<BtcHour> ite = btcHours.iterator();
                while (ite.hasNext()) {
                    BtcHour btcHour = ite.next();
                    if (btcHour.getId() == maxId) {
                        ite.remove();
                        logger.debug("过滤最新的K线："+JSONObject.toJSONString(btcHour));
                    } else {
                        try {
                            btcHourService.insert(btcHour);
                        } catch (DuplicateKeyException e) {
                            logger.debug("record exist");
                        }
                    }
                }
            } catch (ApiException e) {
                logger.debug("API Error! err-code: " + e.getErrCode() + ", err-msg: " + e.getMessage());
                e.printStackTrace();
            }
        }).start();

        return JsonUtil.getSuccessJsonObject();
    }

    @GetMapping(value = "/getByPeriod")
    public JSONObject getByPeriod(@RequestParam("period") String period,@RequestParam("avgNum") Integer avgNum){
        JSONObject result = new JSONObject();
        List<BtcHour> btcHours = btcHourService.getByPeriod(period);
        Collections.sort(btcHours);
        Double[] array = new Double[avgNum];
        JSONArray resultList = new JSONArray();
        if(btcHours.size()>avgNum){
            for(int i=0;i<btcHours.size();i++){
                BtcHour btcHour = btcHours.get(i);
                if(i<avgNum){
                    array[i]=btcHour.getClose();
                }else{
                    array[i%avgNum]=btcHour.getClose();
                    Double avg = getAvg(array);
                    JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(btcHour));
                    jsonObject.put("time", DateUtil.formatDate(btcHour.getTime(),DateUtil.TIME_PATTERN_DISPLAY));
                    jsonObject.put("avg"+avgNum,avg);
                    String optMsg = "";
                    String optStatus = "";
                    if(btcHour.getClose()>avg){
                        optMsg =optMsg+String.format("收盘价："+btcHour.getClose()+" > "+avgNum+"均："+avg+"  ");
                        optStatus = "买入";
                    }else{
                        optMsg =optMsg+String.format("收盘价："+btcHour.getClose()+" < "+avgNum+"均："+avg+"  ");
                        optStatus = "卖出";
                    }
                    jsonObject.put("optMsg",optMsg);
                    jsonObject.put("optStatus",optStatus);
                    resultList.add(jsonObject);
                }
            }
        }
        result.put("resultList",resultList);
        result.put("dealOneList",dealOneList(resultList));
        return JsonUtil.getSuccessJsonObject(result);
    }

    /**
     * 操作逻辑：
     *  1、获取所有4小时k线数据
     *  2、循环以下逻辑
     *      1）、每次4小时k线收盘价 大于 4小时21均线，则加一成仓，直到加满；
     *      2）、只要满足4小时k线收盘价 小于等于 4小时21均线，则全部清仓；
     *
     * @param jsonArray 4小时对应所有的k线数据列表
     * @return
     */
    private JSONArray dealOneList(JSONArray jsonArray) {
        JSONArray resultList = new JSONArray();
        Double holdBtc = 0d;  //持有btc的数量
        Double avgHoldMoney = 0d;  //持有btc的买入均价
        Double remainingMoney = 10000d; //拥有的总金额 1w美金，即剩余总金额
        Double optMoney = remainingMoney*0.1;//每次操作的金额
        Double earningTotal = 0d; // 总收益
        for(int i=0;i<jsonArray.size();i++){
            JSONObject jsonObject = (JSONObject) jsonArray.get(i);
            BtcHour btcHour = JSONObject.parseObject(jsonObject.toJSONString(),BtcHour.class);
            if(jsonObject.getString("optStatus").equals("买入")){
                if(remainingMoney>optMoney){ //可操作的金额必须大于剩余金额
                    logger.debug("\n=========================买入  start=========================");
                    logger.debug(String.format("\n买入前状态：\n持有btc数量:%f\n持有btc的买入均价：%f\n剩余总金额：%f\n总收益：%f\n",
                            holdBtc,avgHoldMoney,remainingMoney,earningTotal));
                    remainingMoney -=optMoney;
                    Double addHoldBtc = divide(optMoney,btcHour.getClose());
                    avgHoldMoney = divide((multiply(holdBtc,avgHoldMoney) + optMoney),holdBtc+addHoldBtc);
                    holdBtc +=addHoldBtc;
                    logger.debug(String.format("\n买入后状态：\n持有btc数量:%f\n持有btc的买入均价：%f\n剩余总金额：%f\n总收益：%f\n",
                            holdBtc,avgHoldMoney,remainingMoney,earningTotal));
                    logger.debug("\n=========================买入  end=========================");

                    JSONObject result = new JSONObject();
                    result.put("持有btc数量",holdBtc);
                    result.put("持有btc的买入均价",avgHoldMoney);
                    result.put("剩余总金额",remainingMoney);
                    result.put("总收益",earningTotal);
                    result.put("操作状态","买入");
                    result.put("optMsg",jsonObject.getString("optMsg"));
                    resultList.add(result);
                }
            }else{
                if(holdBtc>0d){ //可操作的金额必须大于剩余金额
                    logger.debug("\n=========================卖出  start=========================");
                    logger.debug(String.format("\n卖出前状态：\n持有btc数量:%f\n持有btc的买入均价：%f\n剩余总金额：%f\n总收益：%f\n",
                            holdBtc,avgHoldMoney,remainingMoney,earningTotal));
                    earningTotal += multiply((btcHour.getClose()-avgHoldMoney),holdBtc);
                    remainingMoney +=multiply(btcHour.getClose(),holdBtc);
                    holdBtc = 0d;
                    avgHoldMoney = 0d;
                    logger.debug(String.format("\n卖出后状态：\n持有btc数量:%f\n持有btc的买入均价：%f\n剩余总金额：%f\n总收益：%f\n",
                            holdBtc,avgHoldMoney,remainingMoney,earningTotal));
                    logger.debug("\n=========================卖出  end=========================");

                    JSONObject result = new JSONObject();
                    result.put("持有btc数量",holdBtc);
                    result.put("持有btc的买入均价",avgHoldMoney);
                    result.put("剩余总金额",remainingMoney);
                    result.put("总收益",earningTotal);
                    result.put("操作状态","卖出");
                    result.put("optMsg",jsonObject.getString("optMsg"));
                    resultList.add(result);
                }
            }

        }
        return resultList;
    }

    private Double getAvg(Double[] array) {
        Double total = 0.0;
        for(int i=0;i<array.length;i++){
            total +=array[i];
        }
        return divide(total,Double.valueOf(array.length));
    }
    private static Double divide(Double a,Double b) {
        return new BigDecimal(a).divide(new BigDecimal(b),5,BigDecimal.ROUND_HALF_DOWN).doubleValue();
    }
    private static Double multiply(Double a,Double b) {
        return new BigDecimal(a).multiply(new BigDecimal(b)).setScale(5,BigDecimal.ROUND_HALF_DOWN).doubleValue();
    }
}
